package git.soulbgm.socket;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.DatagramPacket;
import io.netty.channel.socket.nio.NioDatagramChannel;

import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;

/**
 * UDP客户端
 *
 * @author SoulBGM
 * @date 2024/04/07
 */
public class UdpClient {

    private static UdpClient client;

    private static NioEventLoopGroup group;
    private static Channel channel;

    /**
     * UDP客户端
     *
     * @throws InterruptedException 中断异常
     */
    private UdpClient() throws InterruptedException {
        group = new NioEventLoopGroup();
        Bootstrap bootstrap = new Bootstrap();
        bootstrap.group(group)
                .channel(NioDatagramChannel.class)
                .option(ChannelOption.IP_MULTICAST_TTL, 16)
                .option(ChannelOption.SO_SNDBUF, 1024 * 1024 * 2)
                .option(ChannelOption.SO_RCVBUF, 1024 * 1024 * 2)
                .option(ChannelOption.RCVBUF_ALLOCATOR, new FixedRecvByteBufAllocator(1024 * 1024 * 2))
                .handler(new SimpleChannelInboundHandler<DatagramPacket>() {
                    @Override
                    protected void channelRead0(ChannelHandlerContext ctx, DatagramPacket msg) throws Exception {

                    }
                });

        channel = bootstrap.bind(0).sync().channel();
    }

    /**
     * 获取UDP客户端
     *
     * @return {@link UdpClient}
     * @throws InterruptedException 中断异常
     */
    public static UdpClient getClient() throws InterruptedException {
        if (client == null) {
            client = new UdpClient();
        }
        return client;
    }

    /**
     * 发送数据
     *
     * @param ip   ip
     * @param port 端口
     * @param data 数据
     */
    public void send(String ip, int port, byte[] data) {
        channel.writeAndFlush(new DatagramPacket(Unpooled.copiedBuffer(data), new InetSocketAddress(ip, port)));
    }

    /**
     * 关闭通道和组
     */
    public static void close() {
        if (channel != null) {
            channel.close();
        }
        if (group != null) {
            group.shutdownGracefully();
        }
    }

    /**
     * 最后确定
     *
     * @throws Throwable 可抛出异常
     */
    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        close();
    }
}
